#include "evilqq.h"
#include "error.h"
#include "tcpip.h"
#include "utils.h"
#include "md5.h"
#include "list.h"

#ifdef MTRACE
#include <mcheck.h>
#endif

extern char *optarg;
extern int optind;
struct ops o;

int main(int argc, char** argv) {
    struct timeval tv;
    int arg;
    
#ifdef MTRACE
    mtrace();
#endif
    
    signal(SIGINT, sigdie);
    signal(SIGTERM, sigdie);
    signal(SIGHUP, sigdie);


    gettimeofday(&tv, NULL);
    if (tv.tv_usec)
        srand(tv.tv_usec);
    else if (tv.tv_sec)
        srand(tv.tv_sec);
    else
        srand(time(NULL));

    options_init();
    if (!o.debugging)
        signal(SIGSEGV, sigdie);
    

    while((arg = getopt(argc, argv, "cdhlt:") != EOF)) {
        switch(arg) {
            case 'c':
                o.color++;
                break;
            case 'd':
                o.debugging++;
                break;
            case 'l':
                o.log++;
                break;
            case 't':
               if (*optarg == '\0'|| *optarg == 'U')
                   o.contype = UDP;
               else if (*optarg == 'T') 
                   o.contype = TCP;
               else if (*optarg == 'P')
                   o.contype = PROXY;
               break;
            case 'h':
            case '?':
               printusage(argv[0]);
               break;
        }     
    }
    clear_screen();
//DO_LOGIN:
    if (argc < 3) {
        unsigned int qqid;
        char *password;
        char encrypted_pass[16];
        qqinfo *qq;

        qq = (qqinfo *)safe_malloc(sizeof(qqinfo));
        bzero(qq, sizeof(qqinfo));

        password = (char *)safe_malloc(32);
        bzero(password, 32);
        
        printf("QQ id: ");
        scanf("%u", &qqid);
        printf("QQ password: ");
        my_getpass("%31s", password);
//        printf("\nuserneme: %d", qqid);
//        printf("\npassword: %s", password);
        
        my_crypt(password, encrypted_pass, strlen(password));
        free(password);
        
        
        qqinfo_create(qq, qqid, encrypted_pass);

        
        
    }


    return 0;
}

   
void options_init() {
    FILE *fp;
    char line [1024];
    char rcfile[1024];


    bzero((char *)&o, sizeof(struct ops));
    o.debugging = DEBUGGING;
    sprintf(rcfile, "%s/.evilqqrc", getenv("HOME"));
    fp = fopen(rcfile, "r");
    if (fp) {
        while (fgets(line, 1023, fp)) {
            char *s;
            char *newline = strchr(line, '\n');
            if (newline != NULL)
                *newline = '\0';
            if (line[0] == '#')
                continue;
            if ((s = strchr(line, '='))) {
                *(s++) = '\0';
                if (strcasecmp(line, "color") == 0) {
                    if (strcasecmp(s, "true") == 0)
                        o.color = 1;
                    else if (strcasecmp(s, "false") == 0)
                        o.color = 0;
                    else
                        fatal("something is wrong with your ~/.evilqqrc");
                }
                else if (strcasecmp(line, "log") == 0) {
                    if (strcasecmp(s, "true") == 0)
                        o.log = 1;
                    else if (strcasecmp(s, "false") == 0)
                        o.log = 0;
                    else
                        fatal("something is wrong with your ~/.evilqqrc");
                }
                else if (strcasecmp(line, "type") == 0) {
                    if (strcasecmp(s, "tcp") == 0)
                        o.contype = TCP;
                    else if (strcasecmp(s, "udp") == 0)
                        o.contype = UDP;
                    else if (strcasecmp(s, "proxy") == 0)
                        o.contype = PROXY;
                    else 
                        fatal("something is wrong with your ~/.evilqqrc");
                }
                else if (strcasecmp(line, "TCPServer") == 0) {
                    if (getserverlist(s, o.tcpserver) == -1) 
                        fatal("somthing is wrong with your ~/.evilqqrc");
                }
                else if (strcasecmp(line, "UDPServer") == 0) {
                    if (getserverlist(s, o.udpserver) == -1)
                        fatal("something is wrong with your ~/.evilqqrc");
                }
                else if (strcasecmp(line, "ProxyServer") == 0) {
                    if (getserverlist(s, o.proxyserver) == -1)
                        fatal("something is wrong with your ~/.evilqqrc");
                }
            }
        }
    }
}

int getserverlist(char *s, server *slist) {
    char *p, *host, *port;
    int res;
    struct in_addr ip;
    server *tmp = slist;
    
    for (p=s; p!=NULL && *p!='\0';) {
        host = p;
        p = strchr(p, ';');
        if (p != NULL)
            *(p++) = '\0';
        port = strchr(host, ':');
        if (port == NULL)
            return -1;
        *(port++) = '\0';
        res = resolve(host, &ip);
        if (res == 0)
            continue;
        tmp = (server *)safe_malloc(sizeof(server));
        bzero(tmp, sizeof(server));
        tmp->host = ip;
        tmp->portno = atoi(port);
        tmp->next = NULL;
        tmp = tmp->next;
    }
    return 0;
}

void sigdie(int signo) {
    switch(signo) {
        case SIGINT:
            fprintf(stderr, "caught SIGINT signal, cleaning up\n");
            break;
        case SIGTERM:
            fprintf(stderr, "caught SIGTERM signal, cleaning up\n");
            break;
        case SIGHUP:
            fprintf(stderr, "caught SIGHUP signal, cleaning up\n");
            break;
        case SIGSEGV:
            fprintf(stderr, "caught SIGSEGV signal, cleaning up\n");
            break;
        case SIGBUS:
            fprintf(stderr, "caught SIGBUS signal, cleaning up\n");
            break;
        default:
            fprintf(stderr, "caught signal %d, cleaning up\n", signo);
            break;
    }
    fflush(stdout);
    exit(1);
}

void printusage(char *name) {
    exit(1);
}

void clear_screen() {                       //I don't know HOW it works, but it works.
    printf("\033[2J   \033[0;0f");
}

int my_getpass(const char *fmt, ...) {      //Just copy from the getpass info page with
    struct termios old, new;                //some changes.
    int nread;
    va_list ap;
    va_start(ap, fmt);

    if (tcgetattr(fileno(stdin), &old) != 0)
        return -1;
    new = old;
    new.c_lflag &= ~ECHO;
    if (tcsetattr(fileno(stdin), TCSAFLUSH, &new) != 0)
        return -1;

    nread = vfscanf(stdin, fmt, ap);
    (void) tcsetattr(fileno(stdin), TCSAFLUSH, &old);

    return nread;
}
void my_crypt(const char *pass, char *encypted, int passlen) {
    md5_state_t mst;
    md5_init(&mst);
    md5_append(&mst, (md5_byte_t *)pass, passlen);
    md5_finish(&mst, (md5_byte_t *)encypted);
}
    
void qqinfo_create(qqinfo *qq, unsigned int qqid, char *password) {
    qq->id = qqid;
    
    my_crypt(password, qq->encrypted_password, 16);
    // make encrypted_password_v2011 for qq 2011 or newer version
    char source[24] = {0};
    memcpy(source, password, 16);
    *(unsigned int *)&source[20] = htonl(qqid);
    my_crypt(source, qq->encrypted_password_v2011, 24);
    
    qq->st = QQ_ONLINE;
    qq->process = P_INIT;
    qq->version = VERSION;

    list_create(&qq->buddy_list, MAX_BUDDY);
    list_create(&qq->qun_list, MAX_QUN);
    list_create(&qq->group_list, MAX_GROUP);

    

    
}
